home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 129_01.zip / 210ROOMA.C < prev    next >
Text File  |  1993-06-01  |  22KB  |  746 lines

  1. /************************************************************************/
  2. /*                rooma.c                 */
  3. /*        room code for Citadel bulletin board system        */
  4. /************************************************************************/
  5.  
  6. /************************************************************************/
  7. /*                history                 */
  8. /*                                    */
  9. /* 84Dec20 HAW&JLS The vp union eliminated from the system.        */
  10. /* 84Sep16 HAW    #if put in to handle CP/M-85 bug.            */
  11. /* 84Aug23 JLS & HAW  JLS's <F>orget Room Scheme implemented.        */
  12. /* 84Jul12 JLS & HAW  gotoRoom() and dumpRoom() modified for <S>kip.    */
  13. /* 84Jun23 HAW    Files now checked for CP/M R/O status.            */
  14. /* 84Jun23 HAW & JLS  Unused locals are zapped                */
  15. /* 84Apr04 HAW    Start 1.50a update                    */
  16. /* 83Feb24    Insert check for insufficient RAM, externs too low.    */
  17. /* 82Dec06 CrT    2.00 release.                        */
  18. /* 82Nov05 CrT    main() splits off to become citadel.c            */
  19. /************************************************************************/
  20.  
  21. #include <210ctdl.h>
  22.  
  23. /************************************************************************/
  24. /*                Contents                */
  25. /*                                    */
  26. /*    dumpRoom()        tells us # new messages etc        */
  27. /*    fileDir()        prints out a filename for a dir listing */
  28. /*    fillMailRoom()        set up Mail> from log record        */
  29. /*    gotoRoom()        handles "g(oto)" command for menu    */
  30. /*    init()            system startup initialization        */
  31. /*    initCitadel()                            */
  32. /*    initSysop()                            */
  33. /*    listRooms()        lists known rooms            */
  34. /*    openFile()        opens a .sys file            */
  35. /*    readSysTab()        restores system state from citadel.tab    */
  36. /*    roomExists()        returns slot# of named room else ERROR    */
  37. /*    setSpace()        set default disk and user#        */
  38. /*    setUp()                             */
  39. /*    systat()        shows current system status        */
  40. /*    wildCard()        expands ambiguous filenames        */
  41. /*    writeSysTab()        saves state of system in citadel.tab    */
  42. /*                                    */
  43. /************************************************************************/
  44.  
  45.  
  46. /************************************************************************/
  47. /*    dumpRoom() tells us # new messages etc                */
  48. /************************************************************************/
  49. dumpRoom()
  50. {
  51.     char hasSkipped, str[NAMESIZE];
  52.     int  fileDir();
  53.     int  i, count, loc, newCount, no;
  54.  
  55.     for (newCount=0, count=0, i=0;   i<MSGSPERRM;   i++) {
  56.  
  57.     loc    = roomBuf.msg[i].rbmsgLoc;
  58.     no    = roomBuf.msg[i].rbmsgNo ;
  59.     if (loc != ERROR) {
  60.         /* comparisons which take 64K wraparound into account:    */
  61.         if (no - oldestLo
  62.         < 0x8000
  63.         ) {
  64.         count++;
  65.         }
  66.  
  67.         /* don't boggle -- just checking against newestLo as of */
  68.         /* the last time we were  in this room:            */
  69.         if (no -
  70.            (logBuf.lbvisit[ logBuf.lbgen[thisRoom] & CALLMASK ]+1)
  71.         < 0x8000
  72.         ) {
  73.         newCount++;
  74.         }
  75.     }
  76.     }
  77.     /* lazy patch: */
  78.     if (newCount > count)   newCount = count;
  79.  
  80.     mPrintf(" %d messages\n ", count);
  81.     if (loggedIn && newCount > 0)   mPrintf(" %d new\n", newCount);
  82.     if ((roomBuf.rbflags & CPMDIR) && !expert) {
  83.     /* list directory also: */
  84.     doCR();
  85.     wildCard(fileDir, "*.*");
  86.     }
  87.  
  88.     for (i = LOBBY, hasSkipped = FALSE; i < MAXROOMS; i++)
  89.     if (roomTab[i].rtflags & INUSE &&
  90.            roomTab[i].rtgen == (logBuf.lbgen[i] >> GENSHIFT)) {
  91.         if (roomTab[i].rtflags & SKIP)
  92.         hasSkipped = TRUE;
  93.         else
  94.         if (roomTab[i].rtlastMessage - (
  95.             logBuf.lbvisit[logBuf.lbgen[i] & CALLMASK] + 1)
  96.                     < 0x8000)
  97.             break;
  98.     }
  99.  
  100.     if (i == MAXROOMS && hasSkipped) {
  101.     mPrintf("\n Skipped rooms: \n ");
  102.     for (i = LOBBY; i < MAXROOMS; i++)    /* No need to match gen #s. */
  103.         if (roomTab[i].rtflags & SKIP &&
  104.                roomTab[i].rtflags & INUSE) {
  105.         roomTab[i].rtflags &= ((BYTE - 1) - SKIP);   /* Clear. */
  106.         strcpy(str, roomTab[i].rtname);
  107.         if (roomTab[i].rtflags & CPMDIR)    strcat(str, ":");
  108.         else                    strcat(str, ">");
  109.         if (!(roomTab[i].rtflags & PUBLIC)) strcat(str, "*");
  110.         mPrintf(" %s ", str);
  111.         }
  112.     }
  113. }
  114.  
  115.  
  116. /************************************************************************/
  117. /*    fileDir() prints out one filename and size, for a dir listing    */
  118. /************************************************************************/
  119. fileDir(fileName)
  120. char *fileName;
  121. {
  122.     struct fcb    block;
  123.  
  124.     char tempName[NAMESIZE], tBuf[2*NAMESIZE];
  125.  
  126.     outFlag = OUTOK;
  127.  
  128.     unspace(fileName, tempName);
  129.     setFcb(&block,    tempName);
  130.     bdos(GETfILEsIZE, &block);        /* very slow on MMS BIOS! */
  131.  
  132.     FDSectCount    += block.fcbRecn;
  133.  
  134.     sprintf(tBuf, "%s%5d  ", fileName, block.fcbRecn);
  135.     putWord(tBuf);
  136.     mAbort();        /* chance to next(!)/pause/skip */
  137. }
  138.  
  139. /************************************************************************/
  140. /*    fillMailRoom()                            */
  141. /************************************************************************/
  142. fillMailRoom()
  143. {
  144.     int i;
  145.  
  146.     /* mail room -- copy messages in logBuf to room: */
  147.     for (i=0;  i<MSGSPERRM;  i++) {
  148.     roomBuf.msg[i].rbmsgLoc  = ERROR;
  149.     roomBuf.msg[i].rbmsgNo     = ERROR;
  150.     }
  151.     for (i=0;  i<MAILSLOTS;  i++) {
  152.     if (i==MSGSPERRM)   break;  /* for MSGSPRRM < MAILSLOTS */
  153.     roomBuf.msg[i].rbmsgLoc  = logBuf.lbslot[i];
  154.     roomBuf.msg[i].rbmsgNo     = logBuf.lbId[i]  ;
  155.     }
  156.     noteRoom();
  157. }
  158.  
  159. /************************************************************************/
  160. /*    gotoRoom() is the menu fn to travel to a new room        */
  161. /*    returns TRUE if room is Lobby>, else FALSE            */
  162. /************************************************************************/
  163. char gotoRoom(nam, mode)
  164. char *nam, mode;
  165. {
  166.     int  i, foundit, newStuff, nWest, roomNo;
  167.  
  168.     if (strLen(nam) == 0) {
  169.  
  170.     /* update log entry for current room:    */
  171.     if (mode != 'S') {
  172.         logBuf.lbgen[thisRoom] = roomBuf.rbgen << GENSHIFT;
  173.                  /* Clear SKIP bit */
  174.         roomTab[thisRoom].rtflags &= ((BYTE - 1) - SKIP);
  175.     }
  176.     foundit = FALSE;    /* leaves us in Lobby> if nothing found */
  177.     newStuff= FALSE;
  178.  
  179.     for (i    = 0
  180.          ;
  181.          i<MAXROOMS  &&  !foundit
  182.          ;
  183.          i++
  184.     ) {
  185.         if (
  186.         (roomTab[i].rtflags & INUSE)
  187.         &&
  188.         (roomTab[i].rtgen == (logBuf.lbgen[i] >> GENSHIFT) || aide)
  189.         &&
  190.         (roomTab[i].rtflags & SKIP) == 0
  191.         ) {
  192.         nWest = logBuf.lbvisit[logBuf.lbgen[i] & CALLMASK]+1;
  193.  
  194.         if (roomTab[i].rtlastMessage - nWest  < 0x8000) {
  195.             if (i != thisRoom    &&   (i != AIDEROOM   ||   aide))   {
  196.             foundit = i;
  197.             newStuff= TRUE;
  198.             }
  199.         }
  200.         }
  201.     }
  202.  
  203.     getRoom(foundit);
  204.     mPrintf("%s\n ", roomBuf.rbname);
  205.     } else {
  206.  
  207.     /* non-empty room name, so now we look for it: */
  208.     if (
  209.         (roomNo = roomExists(nam)) == ERROR
  210.         ||
  211.         (roomNo==AIDEROOM  &&  !aide)
  212.     ) {
  213.         mPrintf(" ?no %s room\n", nam);
  214.     } else {
  215.         /* update log entry for current room:   */
  216.         if (mode != 'S') {
  217.         if (loggedIn)
  218.             logBuf.lbgen[thisRoom] = roomBuf.rbgen << GENSHIFT;
  219.         roomTab[thisRoom].rtflags &= ((BYTE - 1) - SKIP);
  220.         }
  221.         getRoom(roomNo);
  222.  
  223.         /* if may have been unknown... if so, note it:    */
  224.         if ((logBuf.lbgen[thisRoom] >> GENSHIFT) != roomBuf.rbgen) {
  225.         logBuf.lbgen[thisRoom] = (
  226.             (roomBuf.rbgen << GENSHIFT) +
  227.             (MAXVISIT -1)
  228.         );
  229.         }
  230.     }
  231.     }
  232.     setUp(FALSE);
  233.     dumpRoom();
  234.     return  newStuff;    /* was thisRoom */
  235. }
  236.  
  237. /************************************************************************/
  238. /*    init() -- master system initialization                */
  239. /************************************************************************/
  240. init() {
  241.     char     getCh(), readSysTab(), toUpper();
  242.     char     *msgFile;
  243.     unsigned codend(), endExt(), externs(), topOfMem();
  244.     int      getText();     /* Forces load in BDS C 1.50a */
  245.  
  246.     whichIO = CONSOLE;
  247.     if (!readSysTab()) exit();
  248.     setSpace(homeDisk, homeUser);
  249.           /* 1K RAM might not actually be sufficient... */
  250.     if (topOfMem() - codEnd() < 1024)    {
  251.     printf("Not enough RAM!");
  252.     exit();
  253.     }
  254.     if (codEnd() > externs())    {
  255.     printf("Externs too low!");
  256.     exit();
  257.     }
  258.  
  259. #ifdef XYZZY
  260.     printf("code ends ....at  %u\n", codend()  );
  261.     printf("externs start at  %u\n", externs() );
  262.     printf("externs end   at  %u\n", endext()  );
  263.     printf("free RAM ends at  %u\n", topofmem());
  264. #endif
  265.  
  266.     exitToCpm    = FALSE;        /* not time to quit yet!    */
  267.     sizeLTentry = sizeOf(logTab[0]);    /* just had to try that feature */
  268.     outFlag    = OUTOK;        /* not p(ausing)        */
  269.  
  270.     pullMessage = FALSE;        /* not pulling a message    */
  271.     pulledMLoc    = ERROR;        /* haven't pulled one either    */
  272.     pulledMId    = ERROR;
  273.  
  274.     debug    = FALSE;
  275.     loggedIn    = FALSE;
  276.     thisRoom    = LOBBY;
  277.  
  278.     whichIO    = CONSOLE;
  279.     loggedIn    = FALSE;
  280.     setUp(TRUE);
  281.  
  282.     /* we initmodem at beginning & end both...*/
  283.     modemInit();
  284.  
  285.     monthTab[1] = "Jan";
  286.     monthTab[2] = "Feb";
  287.     monthTab[3] = "Mar";
  288.     monthTab[4] = "Apr";
  289.     monthTab[5] = "May";
  290.     monthTab[6] = "Jun";
  291.     monthTab[7] = "Jul";
  292.     monthTab[8] = "Aug";
  293.     monthTab[9] = "Sep";
  294.     monthTab[10]= "Oct";
  295.     monthTab[11]= "Nov";
  296.     monthTab[12]= "Dec";
  297.  
  298.     if (!clock)   interpret(pInitDate);
  299.  
  300.     /* open message files: */
  301.     msgFile    = "a:ctdlmsg.sys";
  302.     *msgFile   += msgDisk;
  303.     openFile(msgFile,         &msgfl );
  304.     openFile("ctdlroom.sys", &roomfl);
  305.     openFile("ctdllog.sys",  &logfl );
  306.  
  307.     getRoom(0);       /* load Lobby>  */
  308.     modemInit();
  309. }
  310.  
  311. /************************************************************************/
  312. /*    initCitadel() does not reformat data files            */
  313. /************************************************************************/
  314. initCitadel() {
  315.     whichIO = MODEM;
  316.     setUp(FALSE);
  317. }
  318.  
  319. /************************************************************************/
  320. /*    listRooms() lists known rooms                    */
  321. /************************************************************************/
  322. listRooms(doDull)
  323. char doDull;    /* ALMOST_ALL to list unchanged rooms only    */
  324. {
  325.     char str[NAMESIZE+3];
  326.     char boringRooms, doBoringRooms, hasUnseenStuff, shownHidden, equal;
  327.     int  i;
  328.  
  329.     mPrintf((doDull == FORGOT) ? "\n Forgotten public rooms:\n " :
  330.                  "\n Rooms with unread messages:\n ");
  331.     equal    = TRUE;
  332.     shownHidden = FALSE;
  333.     boringRooms = FALSE;
  334.     doBoringRooms = (doDull == FORGOT) ? FORGOT : UNREAD;
  335.     for (; doBoringRooms <= doDull;  doBoringRooms++) {
  336.     for (i = 0; i < MAXROOMS;  i++) {
  337.         if ((roomTab[i].rtflags & INUSE) && (debug || aide ||
  338.     /* This line checks to see if gen. #s match, saves result in equal */
  339.         (equal=(roomTab[i].rtgen == (logBuf.lbgen[i] >> GENSHIFT))))) {
  340.         /* do only rooms with unseen messages first pass,  */
  341.         /* only rooms without unseen messages second pass: */
  342.         hasUnseenStuff    =  (
  343.             roomTab[i].rtlastMessage - (
  344.             logBuf.lbvisit[ logBuf.lbgen[i] & CALLMASK ]+1
  345.             )  <  0x8000
  346.         );
  347.         if (!hasUnseenStuff)   boringRooms  = TRUE;
  348.  
  349.         if (doDull != FORGOT             &&
  350.             (!doBoringRooms &&    hasUnseenStuff)  ||
  351.             ( doBoringRooms && !hasUnseenStuff)
  352.         ) {
  353.             strcpy(str, roomTab[i].rtname);
  354.  
  355.             if (roomTab[i].rtflags & CPMDIR)    strcat(str, ":");
  356.             else                strcat(str, ">");
  357.  
  358.             if (! (roomTab[i].rtflags & PUBLIC)) {
  359.             strcat(str, "*");
  360.             shownHidden    = TRUE;
  361.             }
  362.             mPrintf(" %s ", str);
  363.         }
  364.         }
  365.         else {
  366.         if (!equal && doDull == FORGOT && roomTab[i].rtflags & PUBLIC)
  367.             mPrintf(" %s%c ", roomTab[i].rtname,
  368.                      (roomTab[i].rtflags & CPMDIR) ? ':' : '>');
  369.         equal = TRUE;
  370.         }
  371.     }
  372.     if (boringRooms && !doBoringRooms  && doDull == ALMOST_ALL)  {
  373.         mPrintf("\n No unseen msgs in:\n ");
  374.     }
  375.     }
  376.     if (!expert && shownHidden) mPrintf("\n \n * => hidden room\n ");
  377. }
  378.  
  379. /************************************************************************/
  380. /*    openFile() opens one of the .sys files.             */
  381. /************************************************************************/
  382. openFile(filename, fd)
  383. char *filename;
  384. int  *fd;
  385. {
  386.     /* open message file */
  387.     if ((*fd = open(filename, 2)) == ERROR) {
  388.     printf("?no %s", filename);
  389.     exit();
  390.     }
  391.     if (file_RO(*fd)) {
  392.     printf("?File %s is R/O!", filename);
  393.     writeSysTab();
  394.     exit();
  395.     }
  396. }
  397.  
  398. /************************************************************************/
  399. /*    readSysTab() restores state of system from SYSTEM.TAB        */
  400. /*    returns:    TRUE on success, else FALSE            */
  401. /*        destroys SYSTEM.TAB after read, to prevent erroneous re-use */
  402. /*        in the event of a crash.                    */
  403. /************************************************************************/
  404. readSysTab() {
  405.     char getc();
  406.     char fBuf[BUFSIZ];
  407.     char *c;
  408.     int  fd;        /* For checking for R/O status */
  409.  
  410.     if ((fd = fopen("ctdlTabl.sys", fBuf)) == ERROR) {
  411.     printf("?no ctdlTabl.sys!");
  412.     return(FALSE);
  413.     }
  414.  
  415.     if (file_RO(fd)) {
  416.     printf("?File ctdltabl.sys is R/O!");
  417.     return(FALSE);
  418.     }
  419.  
  420.     if (
  421.     getw(fBuf) !=  &firstExtern
  422.     ||
  423.     getw(fBuf) !=  &lastExtern
  424.     ) {
  425.     printf("?old ctdlTabl.sys!");
  426.     return(FALSE);
  427.     }
  428.     c    = &firstExtern;
  429.     while (c < &lastExtern)   *c++ = getc(fBuf);
  430.  
  431.     unlink("ctdlTabl.sys");
  432.     return(TRUE);
  433. }
  434.  
  435. /************************************************************************/
  436. /*    roomExists() returns slot# of named room else ERROR        */
  437. /************************************************************************/
  438. int roomExists(room)
  439. char *room;
  440. {
  441.     int i;
  442.  
  443.     for (i=0;  i<MAXROOMS;  i++) {
  444.     if (
  445.         roomTab[i].rtflags & INUSE     &&
  446.         strCmpU(room, roomTab[i].rtname) == SAMESTRING
  447.     ) {
  448.         return(i);
  449.     }
  450.     }
  451.     return(ERROR);
  452. }
  453.  
  454. /************************************************************************/
  455. /*    setSpace() moves us to a disk and user#             */
  456. /************************************************************************/
  457. setSpace(disk, user)
  458. char disk, user;
  459. {
  460.     bdos(SETdISK, disk);
  461.     ourDisk    = disk;
  462.  
  463.     bdos(SETuSER, user);
  464.     ourUser    = user;
  465. }
  466.  
  467. /************************************************************************/
  468. /*    setUp()                             */
  469. /************************************************************************/
  470. setUp(justIn)
  471. char justIn;
  472. {
  473.     int g, i, j, ourSlot;
  474.  
  475.     echo        = BOTH;     /* just in case         */
  476.  
  477.     if (!loggedIn)   {
  478.     prevChar    = ' ';
  479.     termWidth   = 32;
  480.     termLF        = LFMASK;
  481.     termUpper   = TRUE;
  482.     termNulls   = 5;
  483.     expert        = FALSE;
  484.     aide        = FALSE;
  485.  
  486.     if (justIn)   {
  487.         /* set up logBuf so everything is new...        */
  488.         for (i=0;  i<MAXVISIT;  i++)  logBuf.lbvisit[i] = oldestLo;
  489.  
  490.         /* no mail for anonymous folks: */
  491.         roomTab[MAILROOM].rtlastMessage = newestLo;
  492.         for (i=0;  i<MAILSLOTs;  i++)   logBuf.lbId[i]  = 0;
  493.  
  494.         logBuf.lbname[0]    =0;
  495.  
  496.         for (i=0;  i<MAXROOMS;  i++) {
  497.         if (roomTab[i].rbflags & PUBLIC) {
  498.             /* make public rooms known: */
  499.             g            = roomTab[i].rtgen;
  500.             logBuf.lbgen[i]    = (g << GENSHIFT) + (MAXVISIT-1);
  501.         } else {
  502.             /* make private rooms unknown: */
  503.             g            = (roomTab[i].rtgen + (MAXGEN-1)) % MAXGEN;
  504.             logBuf.lbgen[i] = (g << GENSHIFT) + (MAXVISIT-1);
  505.         }
  506.         }
  507.     }
  508.     } else {
  509.     /* loggedIn: */
  510.     termWidth   = logBuf.lbwidth;
  511.     termNulls   = logBuf.lbnulls;
  512.     termLF        = logBuf.lbflags & LFMASK ;
  513.     termUpper   = logBuf.lbflags & UCMASK ;
  514.     expert        = logBuf.lbflags & EXPERT ;
  515.     termTab     = logBuf.lbflags & TABMASK;
  516.     aide        = logBuf.lbflags & AIDE   ;
  517.  
  518.     if (justIn)   {
  519.         /* set gen on all unknown rooms  --  INUSE or no: */
  520.         for (i=0;  i<MAXROOMS;  i++) {
  521.         if (!(roomTab[i].rtflags & PUBLIC)) {
  522.             /* it is private -- is it unknown? */
  523.             if ((logBuf.lbgen[i] >> GENSHIFT)    !=   roomTab[i].rtgen) {
  524.             /* yes -- set    gen = (realgen-1) % MAXGEN */
  525.             j = (roomTab[i].rtgen + (MAXGEN-1)) % MAXGEN;
  526.             logBuf.lbgen[ i ] =  (j << GENSHIFT) + (MAXVISIT-1);
  527.             }
  528.         }
  529.         else if ((logBuf.lbgen[i] >> GENSHIFT)    !=  roomTab[i].rtgen)  {
  530.             /* newly created public room -- remember to visit it; */
  531.             if
  532.              (abs(roomTab[i].rtgen - (logBuf.lbgen[i] >> GENSHIFT))
  533.                        != FORGET_OFFSET)
  534.             logBuf.lbgen[i] = (roomTab[i].rtgen << GENSHIFT) +1;
  535.         }
  536.         }
  537.         /* special kludge for Mail> room, to signal new mail:   */
  538.         roomTab[MAILROOM].rtlastMessage = logBuf.lbId[MAILSLOTS-1];
  539.  
  540.         /* slide lbvisit array down and change lbgen entries to match: */
  541.         for (i=(MAXVISIT-2);  i;  i--) {
  542.         logBuf.lbvisit[i] = logBuf.lbvisit[i-1];
  543.         }
  544.         logBuf.lbvisit[(MAXVISIT-1)]    = oldestLo;
  545.         for (i=0;  i<MAXROOMS;  i++) {
  546.         if ((logBuf.lbgen[i] & CALLMASK)  <  (MAXVISIT-2)) {
  547.             logBuf.lbgen[i]++;
  548.         }
  549.         }
  550.  
  551.         /* Slide entry to top of log table: */
  552.         ourSlot = logTab[thisSlot].ltlogSlot;
  553.         slideltab(0, thisSlot);
  554.  
  555.         logTab[0].ltpwhash        = hash(logBuf.lbpw);
  556.         logTab[0].ltnmhash        = hash(logBuf.lbname);
  557.         logTab[0].ltlogSlot     = ourSlot;
  558.         logTab[0].ltnewest        = newestLo;
  559.     }
  560.     }
  561.     logBuf.lbvisit[0]    = newestLo;
  562.  
  563.     onConsole    = (whichIO == CONSOLE);
  564.     if (thisRoom == MAILROOM)    fillMailRoom();
  565. }
  566.  
  567. /************************************************************************/
  568. /*    systat() prints out current system status            */
  569. /************************************************************************/
  570. systat() {
  571.     int i;
  572.  
  573.     printDate();
  574.  
  575. #ifdef XYZZY
  576.     if (debug) mPrintf(" *catChar=%d catSector=%d\n*", catChar, catSector);
  577. #endif
  578.  
  579.     mPrintf("\n Width %d, %s%slinefeeds, %d nulls\n",
  580.     termWidth,
  581.     termUpper  ?  "UPPERCASE ONLY, " : "",
  582.     termLF       ?  ""         : "no ",
  583.     termNulls
  584.     );
  585.  
  586. #ifdef XYZZY
  587.     if (debug) mPrintf(" *lowId=%u %u, highId=%u %u\n*",
  588.     oldestHi, oldestLo,
  589.     newestHi, newestLo
  590.     );
  591. #endif
  592.  
  593.     if (loggedIn) {
  594.     mPrintf(" Logged in as %s\n", logBuf.lbname);
  595. #ifdef XYZZY
  596.     if (debug) {
  597.         for (i=0; i<MAXVISIT; i++) {
  598.         printf("lbvisit[%d]=%u\n", i, logBuf.lbvisit[i]);
  599.         }
  600.         printf("lbgen>>GENSHIFT==%d; roomTab.rtgen==%d; roomBuf.rbgen==%d\n"
  601.         , logBuf.lbgen[thisRoom]>>GENSHIFT, roomTab[thisRoom].rtgen,
  602.         roomBuf.rbgen
  603.         );
  604.         printf("lbgen&CALLMASK==%d\n", logBuf.lbgen[thisRoom]&CALLMASK);
  605.     }
  606. #endif
  607.     }
  608.  
  609.     mPrintf(" %d messages,",            newestLo-oldestLo +1);
  610.     mPrintf(" last is %u %u,\n",        newestHi, newestLo  );
  611.     mPrintf(" %dK message space,\n",        maxMSector >> 3     );
  612.     mPrintf(" %d-entry log\n",            MAXLOGTAB        );
  613. }
  614.  
  615.  
  616. /************************************************************************/
  617. /*    unspace() copies a filename, removing blanks            */
  618. /************************************************************************/
  619. unspace(from, to)
  620. char *from, *to;
  621. {
  622.     while (*to =  *from++)   if (*to != ' ')   to++;
  623. }
  624.  
  625. /************************************************************************/
  626. /*    writeSysTab() saves state of system in SYSTEM.TAB        */
  627. /*    returns:    TRUE on success, else ERROR            */
  628. /************************************************************************/
  629. writeSysTab() {
  630.     /*    extern int opsLogChar, opsLogSector, catChar, catSector;    */
  631.     /*    extern int lowId, highId, nextRoom;                */
  632.     /*    extern struct logTab, struct roomTab;                */
  633.  
  634.     char *c;
  635.     char fBuf[BUFSIZ];
  636.  
  637.     if(fcreat("ctdlTabl.sys", fBuf) == ERROR) {
  638.     printf("?can't make ctdlTabl.sys");
  639.     return(ERROR);
  640.     }
  641.  
  642.     /* write loc & len so we can detect bad ctdlTabl.sys files: */
  643.     putw(&firstExtern, fBuf);
  644.     putw(&lastExtern,  fBuf);
  645.     c    = &firstExtern;
  646.     while (c < &lastExtern)
  647.     putc(*c++, fBuf);
  648.  
  649.     fclose(fBuf);
  650.     return(TRUE);
  651. }
  652.  
  653. /************************************************************************/
  654. /*    wildCard() Taken from Aug. '84 BYTE Japan report.        */
  655. /************************************************************************/
  656. #define UFNsIZE     13    /* size of "filename.ext" plus a null.    */
  657. #define DEFAULT_DMA    0x80    /* Use default DMA            */
  658.  
  659. wildCard(fn, filename)
  660. int (*fn)();
  661. char *filename;     /* may be ambiguous.  No drive or user numbers. */
  662. {
  663. #ifndef CPM_85_IS_BUGGY
  664.     char fcb[36], *p, *q;
  665.     int  i, s, strCmp(), bdosfn, fileCount;
  666.     struct {
  667.     char unambig[UFNsIZE];    /* filename */
  668.     } *fp;
  669.  
  670.     bdosfn = FINDfIRST;
  671.     setSpace(roomBuf.rbdisk, roomBuf.rbuser);
  672.     bdos(SETdMA, DEFAULT_DMA);
  673.  
  674.     if (filename[1] == ':' || setfcb(fcb, filename) == 255 ||
  675.     (i = bdos(FINDfIRST, fcb)) == 255) {
  676.     /* no such file */
  677.     mPrintf("no %s\n ", filename);
  678.     setSpace(homeDisk, homeUser);
  679.     return;
  680.     }
  681.  
  682.     fp          = msgBuf.mbtext;
  683.     fileCount = 0;
  684.  
  685.     while ((i = bdos(bdosfn, fcb)) != 255) {
  686.     if (fp > (&msgBuf.mbtext[MAXTEXT-100])) {
  687.         printf("too many files!!\n");
  688.         setSpace(homeDisk, homeUser);
  689.         return;
  690.     }
  691.     bdosfn = FINDnEXT;
  692.     if (unpack(i * 32 + 0x81, fp)) {
  693.         fileCount++;
  694.         fp++;
  695.     }
  696.     }
  697.  
  698.     if (fileCount == 0)         /* no such file */
  699.     mPrintf("no %s\n ", filename);
  700.     else {
  701.     qSort(msgBuf.mbtext, fileCount, UFNsIZE, strCmp);
  702.     outFlag     = OUTOK;
  703.     for (fp = msgBuf.mbtext;  fileCount-- && outFlag != OUTSKIP;  fp++)
  704.         (*fn)(fp);
  705.     }
  706.     setSpace(homeDisk, homeUser);
  707. #else
  708.     char buf[BUFSIZ];
  709.  
  710.     if (index(filename, "*") != ERROR ||
  711.     index(filename, "?") != ERROR) {
  712.     /* no such file */
  713.     mPrintf("Sorry, CP/M-85 won't let us process wildcards\n ");
  714.     return;
  715.     }
  716.     setSpace(roomBuf.rbdisk, roomBuf.rbuser);
  717.     if (filename[1] == ':' || fopen(filename, buf) == ERROR) {
  718.     mPrintf("no %s\n ", filename);
  719.     }
  720.     else {
  721.     fclose(buf);
  722.     (*fn)(filename);
  723.     }
  724.     setSpace(homeDisk, homeUser);
  725. #endif
  726. }
  727.  
  728. unpack(pdir, name)
  729. char *pdir, *name;
  730. {
  731.     int i, j;
  732.     char *p;
  733.  
  734.     if (pdir[9] > 128) return FALSE;    /* SYS file. */
  735.     p = name;
  736.     for (i = j = 0; i < 12; i++) {
  737.     if (i == 8) *p++ = '.';
  738.     *p++ = pdir[j++] & '\177';
  739.     }
  740.     *p = '\0';
  741.     return TRUE;
  742. }
  743. nt == 0)         /* no such file */
  744.     mPrintf("no %s\n ", filename);
  745.     else {
  746.     qSort(msgBuf.mbtext, f